/*
 *  CollisionSystem.h
 *  GLRender
 *
 *  Created by Patrick zulian on 5/18/10.
 *  Copyright 2010 University  of Lugano. All rights reserved.
 *
 */

#ifndef COLLISION_SYSTEM_H
#define COLLISION_SYSTEM_H
#include "Base.h"
#include "Globals.h"
#include "WObject.h"
#include <vector>
#include "Utils.h"
#include "AbstractRenderer.h"
#include <set>
#include "constants.h"

class CollisionSystem;

class WNode {
private:
	void init();
	void deleteChildren();
	bool directRemove(WObject * object);
	//static const double TOL = 0.01;
public:
	WNode(const Point3d &min, const Point3d &max);
	WNode();
	virtual
	~WNode();
	
	CollisionSystem * collSys;
	WNode * children[8];
	std::vector< WObject * > objects;
	Point3d min, max;
	
	bool hasChildren;
	unsigned int maxCapacity, level, refCount;
	
	WNode * parent, * root;
	
	
	inline 
	Point3d 
	getSubdivisionIndex(const int i) const;
	
	void
	newSubCellBound(const int subcellNumber, Point3d * cmin, Point3d * cmax) const;
	
	void
	initChildren();
	
	bool insert(WObject * object);
	bool isIn(WObject * object);
	bool remove(WObject * object);
	
	
	void pushDown();
	
	bool checkCollision(WObject * object);
	bool checkCollisions();
	bool areColliding(WObject * obj1, WObject * obj2);
	void renderOn(AbstractRenderer * renderer);
	
	inline
	const Point3d & getMin() const { return min; }
	
	inline
	const Point3d & getMax() const { return max; }
	
	inline
	WNode * getRoot() { if(isRoot()) return this; return root; }
	
	inline
	bool isRoot(){ return root == NULL; }
	
	void reset(const Point3d &min, const Point3d &max);
	
	void clear();
	
	/// NOT WORKING FOR NOW
	void objectMoved(WObject * object,  const int callbackNumber );
	
	bool completelyIn(WObject * object);
	
	bool pushUp(WObject * object);
	
};



struct WNodeLess {
	bool operator() (const WNode  * left, const WNode  * right) const 
	{ 
		return (left->level < right->level) ? true : ( left->level > right->level) ? false : left < right;
	}
};


class CollisionSystem  {
public:
	WNode root;
	std::set< WNode * , WNodeLess > leaves;
	typedef std::set< WNode * , WNodeLess >::iterator LeavesIt;
	int count;
	
	CollisionSystem() : count(0) { root.collSys = this; leafAdded(&root);  };
	
	CollisionSystem(const Point3d &min, const Point3d &max)
	: root(min, max), count(0) {  root.collSys = this; leafAdded(&root); }
	
	virtual
	~CollisionSystem() {  }
	
	inline
	bool isIn(WObject * object) { return root.isIn(object); }
	
	inline
	bool insert(WObject * object) { if(root.insert(object)) { count++; return true; } return false; }
	
	inline
	bool remove(WObject * object) { if(root.remove(object)) { count--; return true; } return false; }
	
	inline
	bool checkCollision(WObject * object) { return root.checkCollision(object); }
	
	inline
	void renderOn(AbstractRenderer * renderer) { root.renderOn(renderer); }
	
	inline
	bool isEmpty() const { return count == 0; }
	
	inline
	void leafAdded(WNode * leaf) { leaf->collSys = this; leaves.insert(leaf); }
	
	inline
	void leafRemoved(WNode * leaf) {  if(leaves.empty()) return; leaves.erase(leaf); }
	
	inline
	void clear() { root.clear(); leaves.clear(); count = 0; }
	
	inline
	void reset(const Point3d &min, const Point3d &max) { root.reset(min, max); leaves.clear(); count = 0; }
	
	bool checkCollisions();
	
	
	
	
};



#endif
